#include "StdAfx.h"
#include "Booker.h"
#include "SubpixelInfoProvider.h"
#include <algorithm>
#include <cassert>

static const int kBufferLength = 0x1000;
static const int kBufferSizeInBytes = kBufferLength * sizeof(SubpixelInfo**);

Booker::Booker()
	: mBuffers(1, (SubpixelInfo**)::malloc(kBufferSizeInBytes)),
	mLastBuffer(mBuffers.front()),
	mIndexOfLastBuffer(0), mNextPositionInsideLastBuffer(0)
{
}

Booker::~Booker()
{
	std::for_each(mBuffers.begin(), mBuffers.end(), ::free);
}

//////////////////////////////////////////////////////////////

void Booker::AddReference(SubpixelInfo* inInfo)
{
	if (mNextPositionInsideLastBuffer >= kBufferLength)
	{
		++mIndexOfLastBuffer;
		if ((size_t)mIndexOfLastBuffer >= mBuffers.size())
		{
			assert(mIndexOfLastBuffer == mBuffers.size());
			mBuffers.push_back((SubpixelInfo**)::malloc(kBufferSizeInBytes));
		}
		mLastBuffer = mBuffers[mIndexOfLastBuffer];
		mNextPositionInsideLastBuffer = 0;
	}
	mLastBuffer[mNextPositionInsideLastBuffer++] = inInfo;
}
	
void Booker::AddUnmaskedReferencesTo(Booker& inRecipientBooker,
	char inTestMask, char inAddMask) const
{
	int itemIndex = mNextPositionInsideLastBuffer;
	for (int bufferIndex = mIndexOfLastBuffer; 0 <= bufferIndex; --bufferIndex)
	{
		SubpixelInfo** buffer = mBuffers[bufferIndex];
		while (--itemIndex >= 0)
		{
			SubpixelInfo* p = buffer[itemIndex];
			if (0 == (p->occupiedState & inTestMask))
			{
				p->occupiedState |= inAddMask;
				inRecipientBooker.AddReference(p);
			}
		}
		itemIndex = kBufferLength;
	}
}

void Booker::ChangeInfosOccupiedState(char inAddBitsMask, char inClearBitsMask)
{
	const char survivingBits = ~inClearBitsMask;
	int itemIndex = mNextPositionInsideLastBuffer;
	for (int bufferIndex = mIndexOfLastBuffer; 0 <= bufferIndex; --bufferIndex)
	{
		SubpixelInfo** buffer = mBuffers[bufferIndex];
		while (--itemIndex >= 0)
		{
			char& ch = buffer[itemIndex]->occupiedState;
			ch = (ch & survivingBits) | inAddBitsMask;			
		}
		itemIndex = kBufferLength;
	}
}

void Booker::RemoveAllReferences()
{
	// do not free buffers, they will be reused
	mIndexOfLastBuffer = 0;
	mNextPositionInsideLastBuffer = 0;
	mLastBuffer = mBuffers.front();
}